package com.atguigu04.threadsafemore.singleton;

/**
 * ClassName: BankTest
 * Package: com.atguigu04.threadsafemore.singleton
 * Description: 实现线程安全的懒汉式
 *
 * @Author ZY
 * @Create 15:54
 * @Version 1.0
 */
public class BankTest {

    static Bank b1 = null;
    static Bank b2 = null;

    public static void main(String[] args) {
        Thread t1 = new Thread(){
            @Override
            public void run() {
                b1 = Bank.getInstance();
            }
        };
        Thread t2 = new Thread(){
            @Override
            public void run() {
                b2 = Bank.getInstance();
            }
        };
        t1.start();
        t2.start();

        try {
            t1.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        try {
            t2.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println(b1);
        System.out.println(b2);
        System.out.println(b1 == b2);
    }


}


class Bank{

    private Bank(){}
    //指令重排序：防止对象部分初始化就被其他线程访问到.
    //为了避免出现指令重排，需要将instance声明为volatile，
    //确保对象完全初始化后才将其赋值给 instance 变量。
    private static volatile Bank instance = null;//存储单例对象的引用,保存唯一的Bank实例


    //实现线程安全的方式1:同步方法
//    public static synchronized Bank getInstance(){//同步监视器，默认为Bank.class
//        if (instance == null){
//
//            try {
//                Thread.sleep(1000);
//            } catch (InterruptedException e) {
//                e.printStackTrace();
//            }
//
//            instance = new Bank();
//        }
//        return instance;
//    }


    //实现线程安全的方式2:同步代码块
//    public static Bank getInstance(){
//        synchronized (Bank.class) {
//            if (instance == null){
//
//                try {
//                    Thread.sleep(1000);
//                } catch (InterruptedException e) {
//                    e.printStackTrace();
//                }
//
//                instance = new Bank();
//            }
//        }
//        return instance;
//    }


    //实现线程安全的方式3:双重检查
    public static Bank getInstance(){
        // 第一次检查：判断实例是否已经创建，避免不必要的同步
        if (instance == null) {
            // 同步代码块，确保只有一个线程能进入创建实例的代码
            synchronized (Bank.class) {
                // 第二次检查：防止多次创建实例，确保只创建一个实例
                if (instance == null){

                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }

                    instance = new Bank();
                }
            }
        }
        return instance;
    }

}
